package values.avatar
{
import core.manager.battle.BattleManager;

import flash.events.EventDispatcher;
import flash.utils.Dictionary;

import mapengine.interfaces.IMapAvatar;

import mx.utils.UIDUtil;

import utils.PropertyUtil;
import utils.VectorUtil;

import values.buff.BuffValue;
import values.events.AvatarValueEvent;
import values.events.BuffValueEvent;
import values.events.LevelEvent;
import values.events.TechValueEvent;
import values.item.EquipmentItemValue;
import values.item.ItemTemplateKeyType;
import values.item.ItemTemplateValueList;
import values.item.ItemValue;
import values.item.ResourceItemValue;
import values.level.AvatarLevelValue;
import values.skill.IBuffDebuffEffectValue;
import values.skill.SkillTemplateValueList;
import values.skill.SkillValue;
import values.tech.PlayerTechValue;

[Event(name="levelUp", type="values.events.AvatarValueEvent")]
[Event(name="propertyChange", type="values.events.AvatarValueEvent")]
[Event(name="dead", type="values.events.AvatarValueEvent")]
[Event(name="actived", type="values.events.AvatarValueEvent")]
[Event(name="unactived", type="values.events.AvatarValueEvent")]
[Event(name="slotUnlocked", type="values.events.AvatarValueEvent")]
[Event(name="skillChanged", type="values.events.AvatarValueEvent")]
[Event(name="skillLearned", type="values.events.AvatarValueEvent")]
[Event(name="addBuff", type="values.events.AvatarValueEvent")]
[Event(name="removeBuff", type="values.events.AvatarValueEvent")]
[Event(name="addEquipment", type="values.events.AvatarValueEvent")]
[Event(name="removeEquipment", type="values.events.AvatarValueEvent")]
/**
 * AvatarValue
 * @author jliang
 *
 */
public class AvatarValue extends EventDispatcher implements IAvatarValue
{
	//==========================================================================
	//  Constructor
	//==========================================================================
	public function AvatarValue()
	{
		super();
		
		initPropertyPlusers();
	}
	//==========================================================================
	//  Public methods
	//==========================================================================
	/**
	 *  
	 * @param template
	 * @param params 
	 * { 
	 *     level: xx,
	 * 	   xp: xxx,
	 * 	   enhance: [ 0, 0, 0 ],    // [ 战斗强化, 特技强化, 元素强化 ]
	 * 	   equipments: [  ],    // [ EquipmentItemValue ]
	 * 	   unlockedSlots: x,
	 *     skills: [ [ 1, 1 ], [ 2, 1 ], [ 3, 1 ] ],[ 技能key, 技能等级 ],.....
	 *     ultimateSkillLevel: -1 或者 1,2,3,4....
	 *     selectedSkill: 1       技能key,
	 * 	   reward: [0 , 0 , 0]
	 *  }
	 * 
	 */	
	public function initialize(template:AvatarTemplateValue, tech:PlayerTechValue, params:* = null):void
	{
		_template = template;
		
		_maxHP = template.maxHP;
		_initMP = template.initMP;
		_mpRecover = template.mpRecover;
		_normalPower = template.normalPower;
		_skillPower = template.skillPower;
		_elementPower = template.elementPower;
		_normalDefense = template.normalDefense;
		_skillDefense = template.skillDefense;
		_elementDefense = template.elementDefense;
		_normalDamage = template.normalDamage;
		_skillDamage = template.skillDamage;
		_elementDamage = template.elementDamage;
		_moveCapability = template.moveCapability;
		_hitRate = template.hitRate;
		_dodgeRate = template.dodgeRate;
		_penetrateRate = template.penetrateRate;
		_resistRate = template.resistRate;
		_enforceRate = template.enforceRate;
		_blockRate = template.blockRate;
		_blockEffect = template.blockEffect;
		_toughness = template.toughness;
		_critRate = template.critRate;
		_critEffect = template.critEffect;
		_defenseRate = template.defenseRate;
		_suppressRate = template.suppressRate;
		_suppressEffect = template.suppressEffect;
		
		
		if (!params)
		{
			//设置默认数据
			params = {
				xp: 0,
				level: 1,
				enhance: [ 0, 0, 0 ],    // [ 战斗强化, 特技强化, 元素强化 ]
				equipments: [  ],    // [ EquipmentItemValue ]
				unlockedSlots: 2,
				skills: [ [ template.skill.defaultNormalSkill, 1 ] ],
				ultimateSkillLevel: 1,
				selectedSkill: template.skill.defaultNormalSkill,
				reward:[0 , 0 , 0]
			};
		}
		
		//初始化强化属性加成
		EnhancePropertyPluser(enhancePropertyPluser).normalPower = params.enhance[0];
		EnhancePropertyPluser(enhancePropertyPluser).skillPower = params.enhance[1];
		EnhancePropertyPluser(enhancePropertyPluser).elementPower = params.enhance[2];
		
		//初始化属性奖励
		RewardPropertyPluser(rewardPropertyPluser).normalPower = params.reward[0];
		RewardPropertyPluser(rewardPropertyPluser).skillPower = params.reward[1];
		RewardPropertyPluser(rewardPropertyPluser).elementPower = params.reward[2];
		
		//初始化等级和经验值		
		_levelValue = new AvatarLevelValue();
		_levelValue.init(params.level, ItemValue.create(ItemTemplateValueList.getByKey(ItemTemplateKeyType.XP), null, { num: params.xp }) as ResourceItemValue);
		
		levelValue.addEventListener(LevelEvent.LEVEL_CHANGED, levelChangedHandler);
		
		//处理成长值
		updateGrowPropertyPlus();
		
		//初始化装备
		for each (var equipObj:Array in params.equipments)
		{
			var equipment:EquipmentItemValue = ItemValue.create(ItemTemplateValueList.getByKey(equipObj[1]), equipObj[0], equipObj[2]) as EquipmentItemValue;
			addEquipment(equipment);
		}
		
		//初始化科技
		if(tech)
		{
			_playerTechValue = tech;
			playerTechValue.addEventListener(TechValueEvent.LEVEL_UP, techLevelUpHandler);
			updateTechPropertyPlus();
		}
		
		//初始化技能
		var skillMap:Dictionary = new Dictionary(true);
		
		var skillVO:SkillValue;
		
		for (var i:int = 0; i < template.skill.normalSkills.length; i++)
		{
			var skillKey:String = template.skill.normalSkills[i];
			skillVO = SkillValue.create(SkillTemplateValueList.getByKey(skillKey), this, 1 , i);
			skills.push(skillVO);
			skillMap[skillVO.key] = skillVO;
		}
		
		var skillList:Array = Object(params).hasOwnProperty("skills") ? params.skills : [];
		for (var j:int = 0; j < skillList.length; j++)
		{
			skillVO = skillMap[skillList[j][0]];
			unlockSlot(skillVO.slot);
			learnSkill(skillVO.key, skillList[j][1]);
		}
		
		//初始化当前技能
		changeSkill(params.selectedSkill);
		
		//初始化奥义技能		
		_ultimateSkill = SkillValue.create(SkillTemplateValueList.getByKey(template.skill.ultimateSkill), this, 1 , -1);
		
		var ultimateSkillLevel:int = Object(params).hasOwnProperty("ultimateSkillLevel") ? params.ultimateSkillLevel : 0;
		if (ultimateSkillLevel > 0)
		{
			learnSkill(template.skill.ultimateSkill, ultimateSkillLevel);
		}
		
		skillMap = null;
		skillVO = null;
		
		//处理所有额外属性加成
		refreshProperties();
	}
	
	public function initBattleState():void
	{
		if(ultimateSkill) ultimateSkill.startBattle();
		currentRoundState = AvatarRoundState.FINISHED;
		hp = maxHP;
		mp = initMP;
	}
	
	//==========================================================================
	//  Properties
	//==========================================================================
	
	private var _currentRoundState:int = AvatarRoundState.MOVE;

	public function get currentRoundState():int
	{
		if(debuff && !debuff.candoThings) return AvatarRoundState.FINISHED;
		if(_currentRoundState == AvatarRoundState.MOVE && (debuff && !debuff.canMove)) return AvatarRoundState.ATTACT; 
		return _currentRoundState;
	}

	public function set currentRoundState(value:int):void
	{
		_currentRoundState = value;
		if( BattleManager.battleManager && value == AvatarRoundState.FINISHED)
		{
			if(buff) buff.effect();
			if(debuff) debuff.effect();
			BattleManager.battleManager.currentAvatar = null;
			BattleManager.battleManager.roundEnd();
		}
	}

	
	protected var _uid:String = UIDUtil.createUID();
	
	public function get uid():String
	{
		return _uid;
	}
	
	public function get type():String
	{
		return "avatar";
	}
	
	public function get width():int
	{
		return 1;
	}
	
	public function get height():int
	{
		return 1;
	}
	
	protected var _x:int = 0;
	
	public function set x(value:int):void
	{
		_x = value;
	}
	
	public function get x():int
	{
		return _x;
	}
	
	protected var _y:int = 0;
	
	public function set y(value:int):void
	{
		_y = value;
	}
	
	public function get y():int
	{
		return _y;
	}
	
	protected var _tempX:int = 0;

	public function get tempX():int
	{
		return _tempX;
	}

	public function set tempX(value:int):void
	{
		_tempX = value;
	}
	
	protected var _tempY:int = 0;

	public function get tempY():int
	{
		return _tempY;
	}

	public function set tempY(value:int):void
	{
		_tempY = value;
	}

	
	protected var _walkable:Boolean = false;

	public function get walkable():Boolean
	{
		return _walkable;
	}

	public function set walkable(value:Boolean):void
	{
		_walkable = value;
	}
	
	protected var _direction:int = 0;

	public function get direction():int
	{
		return _direction;
	}

	public function set direction(value:int):void
	{
		_direction = value;
	}
	
	protected var _template:AvatarTemplateValue;
	
	public function get template():AvatarTemplateValue
	{
		return _template;
	}
	
	public function get key():String
	{
		return template.key;
	}
	
	public function get name():String
	{
		return template.name;
	}
	
	/**
	 * 玩家拥有的科技 
	 */	
	protected var _playerTechValue:PlayerTechValue;

	public function get playerTechValue():PlayerTechValue
	{
		return _playerTechValue;
	}
	
	/**
	 * 角色职业 
	 * @return 
	 * 
	 */	
	public function get avatarType():AvatarTypeValue
	{
		return template.avatarType;
	}
	
	/**
	 * 阵营，0 -> 中立;   1 -> 自己人;  2 -> 友军;   -1 -> 敌对
	 */	
	protected var _party:int = 0;
	
	public function set party(value:int):void
	{
		_party = value;
	}
	
	public function get party():int
	{
		return _party;
	}
	
	public function get isOwen():Boolean
	{
		return party == 1;
	}	
	
	public function get isAlly():Boolean
	{
		return party == 2;
	}
	
	public function get isNeutral():Boolean
	{
		return party == 0;
	}
	
	public function get isEmeny():Boolean
	{
		return party < 0;
	}
	
	protected var _levelValue:AvatarLevelValue;
	
	public function get levelValue():AvatarLevelValue
	{
		return _levelValue;
	}
	
	public function get level():int
	{
		return levelValue.level;
	}
	
	public var aiList:Array;
	
	public function set xp(value:Number):void
	{
		var oldValue:Number = levelValue.resource;
		
		levelValue.resource = value;
		
		var newValue:Number = levelValue.resource;
		
		if (oldValue != newValue)
		{
			dispatchAvatarEvent(AvatarValueEvent.PROPERTY_CHANGE, { avatar:this, property:"xp", oldValue:oldValue, newValue:newValue });
		}
	}
	
	public function get xp():Number
	{
		return levelValue.resource;
	}
	
	public function get isDead():Boolean
	{
		return hp <= 0;
	}
	
	/**
	 * 是否可移动 
	 * @param value
	 * 
	 */	
	protected var _movable:Boolean = true;
	
	public function set movable(value:Boolean):void
	{
		_movable = value;
	}
	
	public function get movable():Boolean
	{
		return _movable;
	}
	
	/**
	 * 是否可攻击 
	 * @param value
	 * 
	 */	
	protected var _attackable:Boolean = true;
	
	public function set attackable(value:Boolean):void
	{
		_attackable = value;
	}
	
	public function get attackable():Boolean
	{
		return _attackable;
	}
	
	/**
	 * 是否可操作 
	 * @param value
	 * 
	 */	
	protected var _active:Boolean = true;
	
	public function set active(value:Boolean):void
	{
		_active = value;
		
		if (active)
		{
			dispatchAvatarEvent(AvatarValueEvent.ACTIVED, { avatar:this });
		}
		else
		{
			dispatchAvatarEvent(AvatarValueEvent.UNACTIVED, { avatar:this });
		}
	}
	
	public function get active():Boolean
	{
		return _active;
	}
	
	/**
	 * 性别     0 -> 女;    1 ->  男
	 * @return 
	 * 
	 */	
	public function get gender():int
	{
		return template.gender;
	}
	
	public function get isMale():Boolean
	{
		return gender == 1;
	}
	
	public function get distance():int
	{
		return template.distance;
	}
	
	/**
	 * 生命值 
	 * @param value
	 * 
	 */	
	protected var _hp:Number = 1;
	
	public function set hp(value:Number):void
	{
		changeProperty("hp", value);
		
		if (hp <= 0)
		{
			dispatchAvatarEvent(AvatarValueEvent.DEAD, { avatar:this });
		}
	}
	
	public function get hp():Number
	{
		return _hp;
	}
	
	/**
	 * 最大生命值 
	 * @param value
	 * 
	 */	
	protected var _maxHP:Number = 1;
	
	public function set maxHP(value:Number):void
	{		
		changeProperty("maxHP", value);
	}
	
	public function get maxHP():Number
	{
		return _maxHP;
	}
	
	/**
	 * 能量值 
	 * @param value
	 * 
	 */	
	protected var _mp:Number = 1;
	
	public function set mp(value:Number):void
	{
		value = Math.min(AvatarTemplateValueList.maxMP , value);
		value = Math.max(0 , value);
		changeProperty("mp", value);
	}
	
	public function get mp():Number
	{
		return _mp;
	}
	
	/**
	 * 最大能量值 
	 * @param value
	 * 
	 */	
	protected var _initMP:Number = 1;
	
	public function set initMP(value:Number):void
	{
		changeProperty("initMP", value);
	}
	
	public function get initMP():Number
	{
		return _initMP;
	}
	
	/**
	 * 能量恢复效率 
	 * @param value
	 * 
	 */	
	protected var _mpRecover:Number = 0;
	
	public function set mpRecover(value:Number):void
	{
		changeProperty("mpRecover", value);
	}
	
	public function get mpRecover():Number
	{
		return _mpRecover;
	}
	
	/**
	 *  战斗
	 * @return 
	 * 
	 */	
	protected var _normalPower:Number = 0;
	
	public function set normalPower(value:Number):void
	{
		changeProperty("normalPower", value);
	}
	
	public function get normalPower():Number
	{
		return _normalPower;
	}
	
	/**
	 *  特技
	 * @return 
	 * 
	 */	
	protected var _skillPower:Number = 0;
	
	public function set skillPower(value:Number):void
	{
		changeProperty("skillPower", value);
	}
	
	public function get skillPower():Number
	{
		return _skillPower;
	}
	
	/**
	 *  元素
	 * @return 
	 * 
	 */	
	protected var _elementPower:Number = 0;
	
	public function set elementPower(value:Number):void
	{
		changeProperty("elementPower", value);
	}
	
	public function get elementPower():Number
	{
		return _elementPower;
	}
	
	/**
	 *  物理防御
	 * @return 
	 * 
	 */	
	protected var _normalDefense:Number = 0;
	
	public function set normalDefense(value:Number):void
	{
		changeProperty("normalDefense", value);
	}
	
	public function get normalDefense():Number
	{
		return _normalDefense;
	}
	
	/**
	 *  特技防御
	 * @return 
	 * 
	 */	
	protected var _skillDefense:Number = 0;
	
	public function set skillDefense(value:Number):void
	{
		changeProperty("skillDefense", value);
	}
	
	public function get skillDefense():Number
	{
		return _skillDefense;
	}
	
	/**
	 *  元素防御
	 * @return 
	 * 
	 */	
	protected var _elementDefense:Number = 0;
	
	public function set elementDefense(value:Number):void
	{
		changeProperty("elementDefense", value);
	}
	
	public function get elementDefense():Number
	{
		return _elementDefense;
	}
	
	/**
	 *  物理攻击
	 * @return 
	 * 
	 */	
	protected var _normalDamage:Number = 0;
	
	public function set normalDamage(value:Number):void
	{
		changeProperty("normalDamage", value);
	}
	
	public function get normalDamage():Number
	{
		return _normalDamage;
	}
	
	/**
	 *  特技攻击
	 * @return 
	 * 
	 */	
	protected var _skillDamage:Number = 0;
	
	public function set skillDamage(value:Number):void
	{
		changeProperty("skillDamage", value);
	}
	
	public function get skillDamage():Number
	{
		return _skillDamage;
	}
	
	/**
	 *  元素攻击
	 * @return 
	 * 
	 */	
	protected var _elementDamage:Number = 0;
	
	public function set elementDamage(value:Number):void
	{
		changeProperty("elementDamage", value);
	}
	
	public function get elementDamage():Number
	{
		return _elementDamage;
	}
	
	/**
	 *  移动力
	 * @return 
	 * 
	 */		
	protected var _moveCapability:Number = 0;
	
	public function set moveCapability(value:Number):void
	{
		value = Math.max(1 , value);
		changeProperty("moveCapability", value);
	}
	
	public function get moveCapability():Number
	{
		return _moveCapability;
	}
	
	/**
	 *  命中等级
	 * @return 
	 * 
	 */	
	protected var _hitRate:Number = 0;
	
	public function set hitRate(value:Number):void
	{
		changeProperty("hitRate", value);
	}
	
	public function get hitRate():Number
	{
		return _hitRate;
	}
	
	/**
	 *  闪避等级
	 * @return 
	 * 
	 */	
	protected var _dodgeRate:Number = 0;
	
	public function set dodgeRate(value:Number):void
	{
		changeProperty("dodgeRate", value);
	}
	
	public function get dodgeRate():Number
	{
		return _dodgeRate;
	}
	
	/**
	 *  穿透等级
	 * @return 
	 * 
	 */	
	protected var _penetrateRate:Number = 0;
	
	public function set penetrateRate(value:Number):void
	{
		changeProperty("penetrateRate", value);
	}
	
	public function get penetrateRate():Number
	{
		return _penetrateRate;
	}
	
	/**
	 *  抵抗等级
	 * @return 
	 * 
	 */	
	protected var _resistRate:Number = 0;
	
	public function set resistRate(value:Number):void
	{
		changeProperty("resistRate", value);
	}
	
	public function get resistRate():Number
	{
		return _resistRate;
	}
	
	/**
	 *  强攻等级
	 * @return 
	 * 
	 */	
	protected var _enforceRate:Number = 0;
	
	public function set enforceRate(value:Number):void
	{
		changeProperty("enforceRate", value);
	}
	
	public function get enforceRate():Number
	{
		return _enforceRate;
	}
	
	/**
	 *  抵挡等级
	 * @return 
	 * 
	 */	
	protected var _blockRate:Number = 0;
	
	public function set blockRate(value:Number):void
	{
		changeProperty("blockRate", value);
	}
	
	public function get blockRate():Number
	{
		return _blockRate;
	}
	
	/**
	 *  抵挡力
	 * @return 
	 * 
	 */	
	protected var _blockEffect:Number = 0;
	
	public function set blockEffect(value:Number):void
	{
		changeProperty("blockEffect", value);
	}
	
	public function get blockEffect():Number
	{
		return _blockEffect;
	}
	
	/**
	 *  强韧等级
	 * @return 
	 * 
	 */	
	protected var _toughness:Number = 0;
	
	public function set toughness(value:Number):void
	{
		changeProperty("toughness", value);
	}
	
	public function get toughness():Number
	{
		return _toughness;
	}
	
	/**
	 *  暴击等级
	 * @return 
	 * 
	 */	
	protected var _critRate:Number = 0;
	
	public function set critRate(value:Number):void
	{
		changeProperty("critRate", value);
	}
	
	public function get critRate():Number
	{
		return _critRate;
	}
	
	/**
	 *  暴击伤害加成
	 * @return 
	 * 
	 */	
	protected var _critEffect:Number = 0;
	
	public function set critEffect(value:Number):void
	{
		changeProperty("critEffect", value);
	}
	
	public function get critEffect():Number
	{
		return _critEffect;
	}
	
	/**
	 *  暴击伤害加成
	 * @return 
	 * 
	 */	
	protected var _defenseRate:Number = 0;
	
	public function set defenseRate(value:Number):void
	{
		changeProperty("defenseRate", value);
	}
	
	public function get defenseRate():Number
	{
		return _defenseRate;
	}
	
	/**
	 *  暴击伤害加成
	 * @return 
	 * 
	 */	
	protected var _suppressRate:Number = 0;
	
	public function set suppressRate(value:Number):void
	{
		changeProperty("suppressRate", value);
	}
	
	public function get suppressRate():Number
	{
		return _suppressRate;
	}
	
	/**
	 *  暴击伤害加成
	 * @return 
	 * 
	 */	
	protected var _suppressEffect:Number = 0;
	
	public function set suppressEffect(value:Number):void
	{
		changeProperty("suppressEffect", value);
	}
	
	public function get suppressEffect():Number
	{
		return _suppressEffect;
	}
	
	/**
	 *  先攻值
	 * @return 
	 * 
	 */		
	protected var _actRate:Number = 0;
	
	public function set actRate(value:Number):void
	{
		changeProperty("actRate", value);
	}
	
	public function get actRate():Number
	{
		return _actRate;
	}
	
	/**
	 *  生命成长值
	 * @return 
	 * 
	 */		
	public function get maxHPGrowRate():Number
	{
		return template.maxHPGrowRate;
	}
	
	/**
	 * 战斗防御成长值 
	 * @return 
	 * 
	 */
	
	public function get normalDefenseGrowRate():Number
	{
		return template.normalDefenseGrowRate;
	}
	
	/**
	 * 技能防御成长值 
	 * @return 
	 * 
	 */	
	public function get skillDefenseGrowRate():Number
	{
		return template.skillDefenseGrowRate;
	}
	
	/**
	 * 元素防御成长值 
	 * @return 
	 * 
	 */	
	public function get elementDefenseGrowRate():Number
	{
		return template.elementDefenseGrowRate;
	}
	
	/**
	 * 战斗攻击成长值 
	 * @return 
	 * 
	 */	
	public function get normalDamageGrowRate():Number
	{
		return template.normalDamageGrowRate;
	}
	
	/**
	 * 特技攻击成长值 
	 * @return 
	 * 
	 */	
	public function get skillDamageGrowRate():Number
	{
		return template.skillDamageGrowRate;
	}
	
	/**
	 * 元素攻击成长值 
	 * @return 
	 * 
	 */	
	public function get elementDamageGrowRate():Number
	{
		return template.elementDamageGrowRate;
	}
	
	/**
	 * 命中等级成长值 
	 * @return 
	 * 
	 */	
	public function get hitRateGrowRate():Number
	{
		return template.hitRateGrowRate;
	}
	
	/**
	 * 闪避等级成长值 
	 * @return 
	 * 
	 */	
	public function get dodgeRateGrowRate():Number
	{
		return template.dodgeRateGrowRate;
	}
	
	/**
	 * 穿透等级成长值 
	 * @return 
	 * 
	 */	
	public function get penetrateRateGrowRate():Number
	{
		return template.penetrateRateGrowRate;
	}
	
	/**
	 * 抵抗等级成长值 
	 * @return 
	 * 
	 */	
	public function get resistRateGrowRate():Number
	{
		return template.resistRateGrowRate;
	}
	
	/**
	 * 强攻等级成长值 
	 * @return 
	 * 
	 */	
	public function get enforceRateGrowRate():Number
	{
		return template.enforceRateGrowRate;
	}
	
	/**
	 * 格挡等级成长值 
	 * @return 
	 * 
	 */	
	public function get blockRateGrowRate():Number
	{
		return template.blockRateGrowRate;
	}
	
	/**
	 * 暴击等级成长值 
	 * @return 
	 * 
	 */	
	public function get critRateGrowRate():Number
	{
		return template.critRateGrowRate;
	}
	
	/**
	 * 强韧等级成长值 
	 * @return 
	 * 
	 */	
	public function get toughnessGrowRate():Number
	{
		return template.toughnessGrowRate;
	}
	
	/**
	 * 压制等级成长值 
	 * @return 
	 * 
	 */	
	public function get suppressRateGrowRate():Number
	{
		return template.suppressRateGrowRate;
	}
	
	/**
	 * 御体等级成长值 
	 * @return 
	 * 
	 */	
	
	public function get defenseRateGrowRate():Number
	{
		return template.defenseRateGrowRate;
	}
	
	/**
	 * 命中加成 
	 * @return 
	 * 
	 */	
	public function get hitRateBonus():Number
	{
		return template.hitRateBonus;
	}
	
	/**
	 * 闪避加成 
	 * @return 
	 * 
	 */	
	public function get dodgeRateBonus():Number
	{
		return template.dodgeRateBonus;
	}
	
	/**
	 * 穿透加成 
	 * @return 
	 * 
	 */	
	public function get penetrateBonus():Number
	{
		return template.penetrateBonus;
	}
	/**
	 * 抵抗加成 
	 * @return 
	 * 
	 */	
	public function get resistRateBonus():Number
	{
		return template.resistRateBonus;
	}
	
	/**
	 * 强攻加成 
	 * @return 
	 * 
	 */	
	public function get enforceRateBonus():Number
	{
		return template.enforceRateBonus;
	}
	/**
	 * 格挡加成 
	 * @return 
	 * 
	 */	
	public function get blockRateBonus():Number
	{
		return template.blockRateBonus;
	}
	
	/**
	 * 格挡效果加成 
	 * @return 
	 * 
	 */	
	public function get blockEffectBonus():Number
	{
		return template.blockEffectBonus;
	}
	
	/**
	 * 暴击加成 
	 * @return 
	 * 
	 */	
	public function get critRateBonus():Number
	{
		return template.critRateBonus;
	}
	
	/**
	 * 强韧加成 
	 * @return 
	 * 
	 */
	public function get toughnessRateBonus():Number
	{
		return template.toughnessRateBonus;
	}
	
	/**
	 * 暴击效果加成 
	 * @return 
	 * 
	 */	
	public function get critEffectBonus():Number
	{
		return template.critEffectBonus;
	}
	
	/**
	 * 压制加成 
	 * @return 
	 * 
	 */	
	public function get suppressRateBonus():Number
	{
		return template.suppressRateBonus;
	}
	
	/**
	 * 御体加成 
	 * @return 
	 * 
	 */	
	public function get defenseRateBonus():Number
	{
		return template.defenseRateBonus;
	}
	
	/**
	 * 压制效果加成 
	 * @return 
	 * 
	 */	
	public function get suppressEffectBonus():Number
	{
		return template.suppressEffectBonus;
	}
	
	////////////////////////////////// 技能 ///////////////////////////////////////////////////
	
	/**
	 * 所学会的技能列表 
	 */	
	protected var skills:Vector.<SkillValue> = new Vector.<SkillValue>();
	
	public function unlockSlot(index:int):void
	{
		var skill:SkillValue = getSkillBySlot(index);
		skill.isUnLocked = true;
		
		dispatchAvatarEvent(AvatarValueEvent.SLOT_UNLOCKED, { avatar:this, slot:index, skill:skill });
	}
	
	/**
	 * 终极技能（奥义） 
	 */	
	protected var _ultimateSkill:SkillValue;
	
	public function get ultimateSkill():SkillValue
	{
		return _ultimateSkill;
	}
	
	protected var _selectedSkill:SkillValue;

	public function get selectedSkill():SkillValue
	{
		return _selectedSkill;
	}
	
	/**
	 *  此方法只针对非奥义技能 
	 * @param skillKey
	 * 
	 */	
	public function changeSkill(skillKey:String):void
	{
		if (selectedSkill && selectedSkill.key == skillKey) return;
		
		var oldSkill:SkillValue = selectedSkill;
		
		_selectedSkill = getSkillByKey(skillKey);
		
		dispatchAvatarEvent(AvatarValueEvent.SKILL_CHANGED, { avatar:this, oldSkill:oldSkill, selectedSkill:selectedSkill });
	}
	
	/**
	 * 此方法只针对非奥义技能 
	 * @param slot
	 * @return 
	 * 
	 */	
	public function getSkillBySlot(slot:int):SkillValue
	{
		return skills[slot];
	}
	
	public function getSkillByKey(skillKey:String):SkillValue
	{
		if (ultimateSkill && ultimateSkill.key == skillKey) return ultimateSkill;
		
		for each (var skill:SkillValue in skills)
		{
			if (skill.key == skillKey) return skill;
		}
		
		return null;
	}
	
	/**
	 * 学习或者升级技能 
	 * @param skillTemplate
	 * @param skillLevel
	 * 
	 */	
	public function learnSkill(skillKey:String, skillLevel:int = 1):void
	{
		var skill:SkillValue = getSkillByKey(skillKey);
		
		//判断是否是奥义技能
		if (skillKey == template.skill.ultimateSkill)
		{
			skill = ultimateSkill;
			ultimateSkill.isUnLocked = true;
		}
		
		skill.level = skillLevel;
		
		PropertyUtil.updateAvatarPluserProperty(this , skillPropertyPluser , skill , 1);
		
		dispatchAvatarEvent(AvatarValueEvent.SKILL_CHANGED, { avatar:this, skill:skill });
	}
	
	public function hasLearnSkill(skillKey:String):Boolean
	{
		return getSkillByKey(skillKey).isUnLocked;
	}
	
	public function get hasLearnUltimateSkill():Boolean
	{
		return ultimateSkill.isUnLocked;
	}
	
	//////////////////////// 战斗的Buff和debuff  ////////////////////////////////////////////////////////
	
	private var _debuff:IBuffDebuffEffectValue;
	
	public function get debuff():IBuffDebuffEffectValue
	{
		return _debuff;
	}
	
	private var _buff:IBuffDebuffEffectValue;
	
	public function get buff():IBuffDebuffEffectValue
	{
		return _buff;
	}
	
	public function set debuff(value:IBuffDebuffEffectValue):void
	{
		if(_debuff)
		{
			_debuff.remove();
			_debuff.dispose();
			_debuff = null;
		}
		_debuff = value;
		
		this.dispatchAvatarEvent(AvatarValueEvent.ADD_WAR_DEBUFF , value);
	}
	
	public function set buff(value:IBuffDebuffEffectValue):void
	{
		if(_buff)
		{
			_buff.remove();
			_buff.dispose();
			_buff = null;
		}
		
		_buff = value;
		
		this.dispatchAvatarEvent(AvatarValueEvent.ADD_WAR_BUFF , value);
	}
	
	
	////////////////////////////////////avatar//////////////////////////////////////////////
	
	protected var _avatar:IMapAvatar;
	
	public function set avatar(value:IMapAvatar):void
	{
		_avatar = value;
	}
	
	public function get avatar():IMapAvatar
	{
		return _avatar;
	}
	
	
	
	////////////////////////  Buff  ////////////////////////////////////////////////////////
	/**
	* Buff 列表 
	* @return 
	* 
	*/	
	protected var _buffs:Vector.<BuffValue> = new Vector.<BuffValue>();
	
	public function get buffs():Vector.<BuffValue>
	{
		return _buffs;
	}
	
	/**
	 * 新增一个buff 
	 * @param name
	 * @param desc
	 * @param icon
	 * @param type
	 * @param time
	 * @param params
	 * 
	 */	
	public function addBuff(name:String, desc:String, icon:String, type:int, time:int, params:*):void
	{
		var buff:BuffValue = new BuffValue();
		buff.name = name;
		buff.desc = desc;
		buff.icon = icon;
		buff.type = type;
		buff.time = time;
		buff.params = params;
		
		var sameTypeBuff:BuffValue;
		
		for each (var temp:BuffValue in buffs)
		{
			if (temp.type == type)
			{
				sameTypeBuff = temp;
				break;
			}
		}
		
		if (sameTypeBuff) removeBuff(sameTypeBuff);
		
		buff.addEventListener(BuffValueEvent.BUFF_END, buffEndHandler);
		
		buffs.push(buff);
		
		dispatchAvatarEvent(AvatarValueEvent.ADD_BUFF, { avatar: this, buff: buff });
	}
	
	/**
	 * 移除一个buff 
	 * @param buff
	 * 
	 */	
	public function removeBuff(buff:BuffValue):void
	{
		VectorUtil.removeObject(buff, buffs);
		
		buff.removeEventListener(BuffValueEvent.BUFF_END, buffEndHandler);
		
		dispatchAvatarEvent(AvatarValueEvent.REMOVE_BUFF, { avatar: this, buff: buff });
	}
	
	//////////////////////// 装备  ////////////////////////////////////////////////////////
	
	protected var equips:Dictionary = new Dictionary(true);  /* EquipmentItemValue */
	
	public function get hasEquipment():Boolean
	{
		var i:int = 0;
		for each(var itemP:* in equips)
		{
			i++;
		}
		
		if(i == 0)
		{
			return false;
		}
		
		return true;
	}
	
	/**
	* 获得某部位上的装备 
	* @param positionKey
	* @return 
	* 
	*/	
	public function getEquipmentByPosition(positionKey:String):EquipmentItemValue
	{
		return equips[positionKey];
	}
	
	/**
	 * 装备一样物品 
	 * @param item
	 * 
	 */	
	public function addEquipment(item:EquipmentItemValue):void
	{
		var oldItem:EquipmentItemValue = getEquipmentByPosition(item.equipmentTemplate.position);
		
		if (oldItem)
		{
			removeEquipment(oldItem);
		}
		
		equips[item.equipmentTemplate.position] = item;
		
		item.owner = this;
		
		PropertyUtil.updateAvatarPluserProperty(this, equipmentPropertyPluser, item, 1);
		
		dispatchAvatarEvent(AvatarValueEvent.ADD_EQUIPMENT, { avatar:this, equipment:item });
	}
	
	/**
	 * 拿下一件装备 
	 * @param item
	 * 
	 */	
	public function removeEquipment(item:EquipmentItemValue):void
	{		
		var oldItem:EquipmentItemValue = getEquipmentByPosition(item.equipmentTemplate.position);
		
		if (oldItem == item)
		{
			delete equips[oldItem.equipmentTemplate.position];
			
			PropertyUtil.updateAvatarPluserProperty(this, equipmentPropertyPluser, oldItem, -1);
			
			item.owner = null;
			
			dispatchAvatarEvent(AvatarValueEvent.REMOVE_EQUIPMENT, { avatar:this, equipment:item });			
		}
	}
	
	/**
	 * 判断是否能装备某样物品 
	 * @param item
	 * @return 
	 * 
	 */	
	public function canEquipItem(item:EquipmentItemValue):Boolean
	{
		return avatarType.canSupportEquip(item.equipmentTemplate.equipType);
	}
	
	/**
	 * 获取当前的角色形象 
	 * @return 
	 * 
	 */	
	public function get skinAsset():AvatarAssetValue
	{
		return template.getSkinAssetByLevel();
	}
	
	/**
	* 额外属性组
	* @return 
	* 
	*/	
	protected var _propertyPlusers:Dictionary = new Dictionary();   /* IAvatarPropertyPluser */
	
	public function get propertyPlusers():Dictionary 
	{
		return _propertyPlusers;
	}
	
	/**
	 * 获得指定的额外属性组, 默认有 grow, equipment, tech, enhance, buff, temp, vip
	 * @param key
	 * @return 
	 * 
	 */	
	public function getPropertyPluserByKey(key:String):IAvatarPropertyPluser
	{
		return propertyPlusers[key];
	}
	
	protected function get rewardPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.REWARD);
	}
	
	protected function get growPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.GROW);
	}
	
	protected function get equipmentPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.EQUIPMENT);
	}
	
	protected function get techPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.TECH);
	}
	
	protected function get enhancePropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.ENHANCE);
	}
	
	protected function get tempPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.TEMP);
	}
	
	protected function get buffPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.BUFF);
	}
	
	protected function get vipPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.VIP);
	}
	
	protected function get skillPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.SKILL);
	}
	
	protected function get birthChartPropertyPluser():IAvatarPropertyPluser
	{
		return getPropertyPluserByKey(AvatarPropertyPluserType.BIRTH_CHART);
	}
	//==========================================================================
	//  Public methods
	//==========================================================================
	public function dispose():void
	{
		_avatar = null;
		if (levelValue)
		{
			levelValue.removeEventListener(LevelEvent.LEVEL_CHANGED, levelChangedHandler);
			levelValue.dispose();
			_levelValue = null;
		}
		
		if (buffs)
		{
			for each (var buff:BuffValue in buffs)
			{
				buff.removeEventListener(BuffValueEvent.BUFF_END, buffEndHandler);
			}
			_buffs = null;
		}	
		
		if (playerTechValue)
		{
			playerTechValue.removeEventListener(TechValueEvent.LEVEL_UP, techLevelUpHandler);	
		}
	}
	
	public function refreshProperties(properties:* = null):void
	{
		var props:Object = {};
		for each (var pluser:IAvatarPropertyPluser in propertyPlusers)
		{
			var obj:Object = PropertyUtil.handlePluserProperty(pluser, properties);
			
			for (var prop:String in obj)
			{
				if (!props.hasOwnProperty(prop))
				{
					props[prop] = { mapping: obj[prop].mapping, value:0 };
				}
				props[prop].value += obj[prop].value;
			}
		}
		
		for each (var pobj:Object in props)
		{
			this[pobj.mapping] = template[pobj.mapping] + pobj.value;
		}
		
		this.normalDamage = Math.ceil( this.normalDamage + this.normalPower * this.level / 10 );
		this.skillDamage = Math.ceil( this.skillDamage + this.skillPower * 6 / 100 );
		this.elementDamage = Math.ceil( this.elementDamage + this.elementDamage * this.level * 9 / 100 );
		this.normalDefense = Math.ceil( this.normalDefense + this.normalPower * this.level * 7 / 100 );
		this.skillDefense = Math.ceil( this.skillDefense + this.skillPower * this.level / 10 );
		this.elementDefense = Math.ceil( this.elementDefense + this.elementPower * this.level * 65 / 1000  );
	}
	//==========================================================================
	//  Protected methods
	//==========================================================================
	protected function dispatchAvatarEvent(type:String, params:* = null):void
	{
		var evt:AvatarValueEvent = new AvatarValueEvent(type);
		evt.params = params;
		this.dispatchEvent(evt);
	}
	
	protected function initPropertyPlusers():void
	{		
		//Grow
		var pluser:IAvatarPropertyPluser = new GrowPropertyPluser(this, AvatarPropertyPluserType.GROW);
		propertyPlusers[pluser.name] = pluser;
		
		//Equipment
		pluser = new AllPropertyPluser(this, AvatarPropertyPluserType.EQUIPMENT);
		propertyPlusers[pluser.name] = pluser;
		
		//Tech
		pluser = new AllPropertyPluser(this, AvatarPropertyPluserType.TECH);
		propertyPlusers[pluser.name] = pluser;
		
		pluser = new RewardPropertyPluser(this , AvatarPropertyPluserType.REWARD);
		propertyPlusers[pluser.name] = pluser;
		
		//Enhance
		pluser = new EnhancePropertyPluser(this, AvatarPropertyPluserType.ENHANCE);
		propertyPlusers[pluser.name] = pluser;
		
		//命格
		pluser = new AllPropertyPluser(this , AvatarPropertyPluserType.BIRTH_CHART);
		propertyPlusers[pluser.name] = pluser;
		
		//Temp
		pluser = new AllPropertyPluser(this, AvatarPropertyPluserType.TEMP);	
		propertyPlusers[pluser.name] = pluser;
		
		//Buff
		pluser = new AllPropertyPluser(this, AvatarPropertyPluserType.BUFF);	
		propertyPlusers[pluser.name] = pluser;
		
		//VIP
		pluser = new AllPropertyPluser(this, AvatarPropertyPluserType.VIP);	
		propertyPlusers[pluser.name] = pluser;
		
		//SKILL
		pluser = new AllPropertyPluser(this , AvatarPropertyPluserType.SKILL);
		propertyPlusers[pluser.name] = pluser;
	}
	
	protected function updateGrowPropertyPlus():void
	{
		AvatarPropertyPluser(growPropertyPluser).maxHP = Math.ceil(maxHPGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).normalDefense = Math.ceil(normalDefenseGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).skillDefense = Math.ceil(skillDefenseGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).elementDefense = Math.ceil(elementDefenseGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).normalDamage = Math.ceil(normalDamageGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).skillDamage = Math.ceil(skillDamageGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).elementDamage = Math.ceil(elementDamageGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).hitRate = Math.ceil(hitRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).dodgeRate = Math.ceil(dodgeRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).penetrateRate = Math.ceil(penetrateRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).resistRate = Math.ceil(resistRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).enforceRate = Math.ceil(enforceRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).blockRate = Math.ceil(blockRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).toughness = Math.ceil(toughnessGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).critRate = Math.ceil(critRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).defenseRate = Math.ceil(defenseRateGrowRate * (level - 1));
		AvatarPropertyPluser(growPropertyPluser).suppressRate = Math.ceil(suppressRateGrowRate * (level - 1));
	}
	
	protected function updateTechPropertyPlus():void
	{
		PropertyUtil.updateAvatarPluserProperty(this, techPropertyPluser, playerTechValue);
	}
	
	protected function changeProperty(property:String, value:*):void
	{
		var oldValue:Number = this[property];
		
		this["_"+property] = value;
		
		var newValue:Number = this[property];
		
		if (oldValue != newValue)
		{
			dispatchAvatarEvent(AvatarValueEvent.PROPERTY_CHANGE, { avatar:this, property:property, oldValue:oldValue, newValue:newValue });
		}
	}
	//==========================================================================
	//  Event handlers
	//==========================================================================
	protected function levelChangedHandler(event:LevelEvent):void
	{
		dispatchAvatarEvent(AvatarValueEvent.LEVEL_UP, { avatar:this });
	}
	
	protected function buffEndHandler(event:BuffValueEvent):void
	{
		var buff:BuffValue = event.params.buff;
		
		removeBuff(buff);
	}
	
	protected function techLevelUpHandler(event:TechValueEvent):void
	{
		var changedProperties:Vector.<String> = event.params.changedProperties;
		
		var mappingList:Dictionary = PropertyUtil.initPropertyMapping(playerTechValue);
		
		for each (var pstr:String in changedProperties)
		{
			techPropertyPluser[pstr] = playerTechValue[mappingList[pstr].prop];
		}
		
		refreshProperties(changedProperties);
	}
}
}









